﻿using UnityEngine;
using System;
using System.Linq;
using System.Collections;

namespace Hont.AStar
{
    public class HontAStarUnityDebugNode : MonoBehaviour
    {
        [Serializable]
        public class DebugSetting
        {
            [HideInInspector]
            public bool isInPath;
            public bool isBeginNode;
            public bool isEndNode;
            [HideInInspector]
            public bool isDebuger;
            [HideInInspector]
            public Color debugerColor;
            [HideInInspector]
            public string debugerText;
        }

        public HontAStarUnity host;
        [Tooltip("Hot key(I)")]
        public bool isWalkable;
        public DebugSetting debugSetting = new DebugSetting();
        public int cost;
        public int mask;
        [HideInInspector]
        public int astar_x;
        [HideInInspector]
        public int astar_y;
        [HideInInspector]
        public int astar_z;
        public Transform customMappingTransform;
        public Vector3 OutputPosition { get { return transform.localPosition + customMappingTransform.localPosition; } }

        public Position AStarPosition { get { return new Position(astar_x, astar_y, astar_z); } }
        public Bounds Bounds { get { return new Bounds(transform.position, host.MappingSize); } }


        void OnDrawGizmos()
        {
            if (host == null) return;
            if (!host.advanceSetting.drawGizmos) return;
            if (host.gizmosSetting.soloDisplayType == HontAStarUnity.SoloTypeEnum.None) return;
            if (!IsGizmosSizeSoloRange()) return;

            var soloDisplayType = host.gizmosSetting.soloDisplayType;
            var alpha = host.gizmosSetting.alpha;

#if UNITY_EDITOR
            if (UnityEditor.Selection.activeGameObject != null && UnityEditor.Selection.objects.Length < 2)
            {
                var selectionNode = UnityEditor.Selection.activeGameObject.GetComponent<HontAStarUnityDebugNode>();
                if (selectionNode != null)
                {
                    var rate = (selectionNode.transform.position - transform.position).sqrMagnitude / host.MappingSize.sqrMagnitude;
                    alpha = Mathf.Lerp(0.1f, alpha, 1 - rate);
                }
            }
#endif

            if (!debugSetting.isInPath && soloDisplayType == HontAStarUnity.SoloTypeEnum.Path) return;
            if (!isWalkable && soloDisplayType == HontAStarUnity.SoloTypeEnum.Walkable) return;
            if (isWalkable && soloDisplayType == HontAStarUnity.SoloTypeEnum.Obstacle) return;

            var oldMatrix = Gizmos.matrix;
            var oldColor = Gizmos.color;

            Gizmos.matrix = transform.localToWorldMatrix;

            if (soloDisplayType == HontAStarUnity.SoloTypeEnum.Mask)
            {
                var cacheState = UnityEngine.Random.state;
                UnityEngine.Random.InitState(mask);
                Gizmos.color = new Color(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), alpha);
                UnityEngine.Random.state = cacheState;
            }
            else if (soloDisplayType == HontAStarUnity.SoloTypeEnum.Cost)
            {
                var cacheState = UnityEngine.Random.state;
                UnityEngine.Random.InitState(cost);
                Gizmos.color = new Color(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), alpha);
                UnityEngine.Random.state = cacheState;
            }
            else
            {
                if (isWalkable) Gizmos.color = new Color(0, 0, 1, alpha);
                else Gizmos.color = new Color(1, 0, 0, alpha);
            }

            if (debugSetting.isInPath) Gizmos.color = new Color(0, 1, 0, alpha);
            if (debugSetting.isBeginNode || debugSetting.isEndNode) Gizmos.color = new Color(1, 1, 0, alpha);
            if (debugSetting.isDebuger) Gizmos.color = debugSetting.debugerColor;

            if (soloDisplayType != HontAStarUnity.SoloTypeEnum.CenterPoint)
            {
                Gizmos.DrawWireCube(Vector3.zero, host.MappingSize);
                Gizmos.DrawCube(Vector3.zero, host.MappingSize);
            }
            Gizmos.DrawSphere(customMappingTransform.localPosition, host.MappingSize.magnitude * 0.3f * 0.5f);

#if UNITY_EDITOR
            if (debugSetting.isDebuger)
                UnityEditor.Handles.Label(transform.localPosition, debugSetting.debugerText);
#endif

            Gizmos.color = oldColor;
            Gizmos.matrix = oldMatrix;
        }

        void OnDrawGizmosSelected()
        {
            if (host == null) return;
            if (!host.advanceSetting.drawGizmos) return;
            if (host.gizmosSetting.soloDisplayType == HontAStarUnity.SoloTypeEnum.None) return;
            if (!IsGizmosSizeSoloRange()) return;

            var soloDisplayType = host.gizmosSetting.soloDisplayType;

            if (!debugSetting.isInPath && soloDisplayType == HontAStarUnity.SoloTypeEnum.Path) return;
            if (!isWalkable && soloDisplayType == HontAStarUnity.SoloTypeEnum.Walkable) return;
            if (isWalkable && soloDisplayType == HontAStarUnity.SoloTypeEnum.Obstacle) return;

#if UNITY_EDITOR
            if (UnityEditor.Selection.gameObjects.Contains(gameObject))
            {
                if (UnityEditor.Tools.current != UnityEditor.Tool.None || UnityEditor.Tools.current == UnityEditor.Tool.View)
                    UnityEditor.Tools.current = UnityEditor.Tool.None;
            }
#endif

            var oldColor = Gizmos.color;
            var oldMatrix = Gizmos.matrix;

            Gizmos.matrix = transform.localToWorldMatrix;

            if (soloDisplayType != HontAStarUnity.SoloTypeEnum.CenterPoint)
            {
                Gizmos.color = Color.white;
                Gizmos.DrawWireCube(Vector3.zero, host.MappingSize);
            }

#if UNITY_EDITOR
            if (debugSetting.isDebuger)
                UnityEditor.Handles.Label(transform.position, debugSetting.debugerText);
            else
                UnityEditor.Handles.Label(transform.position, cost.ToString());
#endif
            Gizmos.color = oldColor;
            Gizmos.matrix = oldMatrix;
        }

        void OnValidate()
        {
            mask = Mathf.ClosestPowerOfTwo(mask);
        }

        public void Init(HontAStarUnity host, Position astarPos)
        {
            this.host = host;
            this.cost = host.defaultCost;
            this.isWalkable = true;

            this.astar_x = astarPos.X;
            this.astar_y = astarPos.Y;
            this.astar_z = astarPos.Z;
        }

        bool IsGizmosSizeSoloRange()
        {
            if (!host.gizmosSetting.enableSizeSolo) return true;

            var lengthRange = host.gizmosSetting.soloLengthRange;
            var widthRange = host.gizmosSetting.soloWidthRange;
            var heightRange = host.gizmosSetting.soloHeightRange;

            var size = new Vector3(astar_x + 1, astar_y + 1, astar_z + 1);

            var flag = lengthRange.x <= size.x && lengthRange.y >= size.x;
            flag &= widthRange.x <= size.z && widthRange.y >= size.z;
            flag &= heightRange.x <= size.y && heightRange.y >= size.y;

            return flag;
        }
    }
}
